/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut,
    unreachable_code,
    clippy::never_loop
)]

use crate::common::*;

/* Indexes into path_table[] below (order is important). */
// #define SUDO_CONF_PATH_ASKPASS		0
// #define SUDO_CONF_PATH_SESH		    1
// #define SUDO_CONF_PATH_NOEXEC		2
// #define SUDO_CONF_PATH_PLUGIN_DIR	3
// #define SUDO_CONF_PATH_DEVSEARCH	    4
pub const SUDO_CONF_PATH_ASKPASS: libc::c_int = 0;
pub const SUDO_CONF_PATH_SESH: libc::c_int = 1;
pub const SUDO_CONF_PATH_NOEXEC: libc::c_int = 2;
pub const SUDO_CONF_PATH_PLUGIN_DIR: libc::c_int = 3;
pub const SUDO_CONF_PATH_DEVSEARCH: libc::c_int = 4;

pub const __LC_ALL: libc::c_int = 6;
pub const LC_ALL: libc::c_int = __LC_ALL;

/* Values of sudo_conf_group_source() */
// #define GROUP_SOURCE_ADAPTIVE	0
// #define GROUP_SOURCE_STATIC	1
// #define GROUP_SOURCE_DYNAMIC	2
pub const GROUP_SOURCE_ADAPTIVE: libc::c_int = 0;
pub const GROUP_SOURCE_STATIC: libc::c_int = 1;
pub const GROUP_SOURCE_DYNAMIC: libc::c_int = 2;

extern "C" {
    fn fclose(__stream: *mut FILE) -> libc::c_int;
    fn fopen(_: *const libc::c_char, _: *const libc::c_char) -> *mut FILE;
    fn malloc(_: libc::c_ulong) -> *mut libc::c_void;
    fn calloc(_: libc::c_ulong, _: libc::c_ulong) -> *mut libc::c_void;
    fn reallocarray(__ptr: *mut libc::c_void, __nmemb: size_t, __size: size_t)
        -> *mut libc::c_void;
    fn free(__ptr: *mut libc::c_void);
    fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int;
    fn strncmp(_: *const libc::c_char, _: *const libc::c_char, _: libc::c_ulong) -> libc::c_int;
    fn strdup(_: *const libc::c_char) -> *mut libc::c_char;
    fn strndup(_: *const libc::c_char, _: libc::c_ulong) -> *mut libc::c_char;
    fn strrchr(_: *const libc::c_char, _: libc::c_int) -> *mut libc::c_char;
    fn strlen(_: *const libc::c_char) -> libc::c_ulong;
    fn strcasecmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int;
    fn strncasecmp(_: *const libc::c_char, _: *const libc::c_char, _: libc::c_ulong)
        -> libc::c_int;
    fn geteuid() -> __uid_t;
    fn __ctype_b_loc() -> *mut *const libc::c_ushort;
    fn __errno_location() -> *mut libc::c_int;
    fn setlocale(__category: libc::c_int, __locale: *const libc::c_char) -> *mut libc::c_char;
    fn sudo_warn_gettext_v1(
        domainname: *const libc::c_char,
        msgid: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn sudo_warn_nodebug_v1(fmt: *const libc::c_char, _: ...);
    // fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
    fn sudo_secure_file_v1(
        path: *const libc::c_char,
        uid: uid_t,
        gid: gid_t,
        sbp: *mut stat,
    ) -> libc::c_int;
    fn sudo_parseln_v2(
        buf: *mut *mut libc::c_char,
        bufsize: *mut size_t,
        lineno: *mut libc::c_uint,
        fp: *mut FILE,
        flags: libc::c_int,
    ) -> ssize_t;
    fn sudo_strsplit_v1(
        str: *const libc::c_char,
        endstr: *const libc::c_char,
        sep: *const libc::c_char,
        last: *mut *const libc::c_char,
    ) -> *const libc::c_char;
    fn sudo_strtobool_v1(str: *const libc::c_char) -> libc::c_int;
    fn sudo_strtonum(
        _: *const libc::c_char,
        _: libc::c_longlong,
        _: libc::c_longlong,
        _: *mut *const libc::c_char,
    ) -> libc::c_longlong;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        lineno: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    fn sudo_warnx_nodebug_v1(fmt: *const libc::c_char, _: ...);
}

// # define _PATH_SUDO_ASKPASS NULL
macro_rules! _PATH_SUDO_ASKPASS {
    () => {
        0 as *mut libc::c_char
    };
}

// # define _PATH_SUDO_SESH "/usr/libexec/utsudo/sesh"
macro_rules! _PATH_SUDO_SESH {
    () => {
        (b"/usr/libexec/utsudo/utsesh\0" as *const u8 as *const libc::c_char as *mut libc::c_char)
    };
}

// # define _PATH_SUDO_NOEXEC "/usr/libexec/utsudo/utsudo_noexec.so"
macro_rules! _PATH_SUDO_NOEXEC {
    () => {
        (b"/usr/libexec/utsudo/utsudo_noexec.so\0" as *const u8 as *const libc::c_char
            as *mut libc::c_char)
    };
}

// # define _PATH_SUDO_PLUGIN_DIR "/usr/libexec/utsudo/"
macro_rules! _PATH_SUDO_PLUGIN_DIR {
    () => {
        (b"/usr/libexec/utsudo/\0" as *const u8 as *const libc::c_char as *mut libc::c_char)
    };
}

macro_rules! _PATH_SUDO_DEVSEARCH {
    () => {
        (b"/dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev/\0" as *const u8
            as *const libc::c_char as *mut libc::c_char)
    };
}

// # define _PATH_SUDO_CONF	"/etc/utsudo.conf"
macro_rules! _PATH_SUDO_CONF {
    () => {
        (b"/etc/utsudo.conf\0" as *const u8 as *const libc::c_char)
    };
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conf_debug {
    pub entries: C2RustUnnamed_2,
    pub debug_files: sudo_conf_debug_file_list,
    pub progname: *mut libc::c_char,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed_2 {
    pub tqe_next: *mut sudo_conf_debug,
    pub tqe_prev: *mut *mut sudo_conf_debug,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conf_debug_list {
    pub tqh_first: *mut sudo_conf_debug,
    pub tqh_last: *mut *mut sudo_conf_debug,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conf_table {
    pub name: *const libc::c_char,
    pub namelen: libc::c_uint,
    pub parser: Option<
        unsafe extern "C" fn(*const libc::c_char, *const libc::c_char, libc::c_uint) -> libc::c_int,
    >,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conf_data {
    pub disable_coredump: bool,
    pub probe_interfaces: bool,
    pub group_source: libc::c_int,
    pub max_groups: libc::c_int,
    pub debugging: sudo_conf_debug_list,
    pub plugins: plugin_info_list,
    pub path_table: [sudo_conf_path_table; 6],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sudo_conf_path_table {
    pub pname: *const libc::c_char,
    pub pnamelen: libc::c_uint,
    pub dynamic: bool,
    pub pval: *mut libc::c_char,
}

static mut sudo_conf_table: [sudo_conf_table; 5] = [sudo_conf_table {
    name: 0 as *const libc::c_char,
    namelen: 0,
    parser: None,
}; 5];

static mut sudo_conf_var_table: [sudo_conf_table; 5] = [sudo_conf_table {
    name: 0 as *const libc::c_char,
    namelen: 0,
    parser: None,
}; 5];

static mut sudo_conf_data: sudo_conf_data = sudo_conf_data {
    disable_coredump: false,
    probe_interfaces: false,
    group_source: 0,
    max_groups: 0,
    debugging: sudo_conf_debug_list {
        tqh_first: 0 as *const sudo_conf_debug as *mut sudo_conf_debug,
        tqh_last: 0 as *const *mut sudo_conf_debug as *mut *mut sudo_conf_debug,
    },
    plugins: plugin_info_list {
        tqh_first: 0 as *const plugin_info as *mut plugin_info,
        tqh_last: 0 as *const *mut plugin_info as *mut *mut plugin_info,
    },
    path_table: [sudo_conf_path_table {
        pname: 0 as *const libc::c_char,
        pnamelen: 0,
        dynamic: false,
        pval: 0 as *mut libc::c_char,
    }; 6],
};

/*
 * "Set variable_name value"
 */
#[no_mangle]
pub unsafe extern "C" fn parse_variable(
    mut entry: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    let mut var: *mut sudo_conf_table = std::ptr::null_mut::<sudo_conf_table>();
    let mut ret: libc::c_int = 0;

    debug_decl!(SUDO_DEBUG_UTIL);

    var = sudo_conf_var_table.as_mut_ptr();
    while !((*var).name).is_null() {
        if strncmp(entry, (*var).name, (*var).namelen as libc::c_ulong) == 0
            && isblank!(*entry.offset((*var).namelen as isize)) != 0
        {
            entry = entry.offset(((*var).namelen + 1) as isize);

            while isblank!(*entry) != 0 {
                entry = entry.offset(1_isize);
            }

            ret = ((*var).parser).expect("non-null function pointer")(entry, conf_file, lineno);

            if ret != 0 {
                ret = SUDO_DEBUG_INFO;
            } else {
                ret = SUDO_DEBUG_ERROR;
            }
            sudo_debug_printf!(
                ret,
                b"%s: %s:%u: Set %s %s\0" as *const u8 as *const libc::c_char,
                get_function_name!(),
                conf_file,
                lineno,
                (*var).name,
                entry
            );
            debug_return_int!(ret);
        }
        var = var.offset(1);
    } // while !((*var).name).is_null()

    sudo_debug_printf!(
        SUDO_DEBUG_WARN,
        b"%s: %s:%u: unknown setting %s\0" as *const u8 as *const libc::c_char,
        get_function_name!(),
        conf_file,
        lineno,
        entry
    );

    debug_return_int!(false as libc::c_int);
}

/*
 * "Path name /path/to/file"
 * If path is missing it will be set to the NULL pointer.
 */
#[no_mangle]
unsafe extern "C" fn parse_path(
    mut entry: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    let mut entry_end: *const libc::c_char = entry.offset(strlen(entry) as isize);
    let mut ep: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut name: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut path: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut cur: *mut sudo_conf_path_table = std::ptr::null_mut::<sudo_conf_path_table>();
    let mut namelen: size_t = 0 as size_t;

    debug_decl!(SUDO_DEBUG_UTIL);

    'bad: loop {
        name = sudo_strsplit_v1(
            entry,
            entry_end,
            b" \t\0" as *const u8 as *const libc::c_char,
            &mut ep,
        );
        if name.is_null() {
            break 'bad;
        }

        namelen = ep.offset_from(name) as libc::c_long as size_t;

        /* Parse path (if present). */
        path = sudo_strsplit_v1(
            std::ptr::null::<libc::c_char>(),
            entry_end,
            b" \t\0" as *const u8 as *const libc::c_char,
            &mut ep,
        );

        /* Match supported paths, ignoring unknown paths. */
        cur = sudo_conf_data.path_table.as_mut_ptr();
        while !(*cur).pname.is_null() {
            if namelen == (*cur).pnamelen as libc::c_ulong
                && strncasecmp(name, (*cur).pname, (*cur).pnamelen as libc::c_ulong) == 0
            {
                let mut pval: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
                if !path.is_null() {
                    pval = strdup(path);
                    if pval.is_null() {
                        sudo_warnx!(
                            b"%s: %s\0" as *const u8 as *const libc::c_char,
                            get_function_name!(),
                            b"unable to allocate memory\0" as *const u8 as *const libc::c_char
                        );
                        debug_return_int!(-1);
                    } // if !pval.is_null()
                } //  if !path.is_null()

                if (*cur).dynamic {
                    free((*cur).pval as *mut libc::c_void);
                }
                (*cur).pval = pval;
                (*cur).dynamic = true;

                sudo_debug_printf!(
                    SUDO_DEBUG_INFO,
                    b"%s: %s:%u: Path %s %s\0" as *const u8 as *const libc::c_char,
                    get_function_name!(),
                    conf_file,
                    lineno,
                    (*cur).pname,
                    if !pval.is_null() {
                        pval
                    } else {
                        b"(none)\0" as *const u8 as *const libc::c_char
                    }
                );
                debug_return_int!(true as libc::c_int);
            } // if  namelen == (*cur).pnamelen &&

            cur = cur.offset(1_isize);
        } // !(*cur).pname.is_null()

        sudo_debug_printf!(
            SUDO_DEBUG_WARN,
            b"%s: %s:%u: unknown path %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            conf_file,
            lineno,
            entry
        );

        debug_return_int!(false as libc::c_int);

        break 'bad;
    } // 'bad loop

    /* bad:*/
    sudo_warnx!(
        b"invalid Path value \"%s\" in %s, line %u\0" as *const u8 as *const libc::c_char,
        entry,
        conf_file,
        lineno
    );

    debug_return_int!(false as libc::c_int);
}

/*
 * "Debug program /path/to/log flags,..."
 */
#[no_mangle]
unsafe extern "C" fn parse_debug(
    mut entry: *const libc::c_char,
    mut _conf_file: *const libc::c_char,
    mut _lineno: libc::c_uint,
) -> libc::c_int {
    let mut debug_spec: *mut sudo_conf_debug = std::ptr::null_mut::<sudo_conf_debug>();
    let mut debug_file: *mut sudo_debug_file = std::ptr::null_mut::<sudo_debug_file>();
    let mut ep: *const libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut path: *const libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut progname: *const libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut flags: *const libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut entry_end: *const libc::c_char = entry.offset(strlen(entry) as isize);
    let mut pathlen: size_t = 0 as size_t;
    let mut prognamelen: size_t = 0 as size_t;

    debug_decl!(SUDO_DEBUG_UTIL);

    /* Parse progname. */
    progname = sudo_strsplit_v1(
        entry,
        entry_end,
        b" \t\0" as *const u8 as *const libc::c_char,
        &mut ep,
    );
    if progname.is_null() {
        debug_return_int!(false as libc::c_int); /* not enough fields */
    }
    prognamelen = ep.offset_from(progname) as size_t;

    /* Parse path. */
    path = sudo_strsplit_v1(
        std::ptr::null::<libc::c_char>(),
        entry_end,
        b" \t\0" as *const u8 as *const libc::c_char,
        &mut ep,
    );
    if path.is_null() {
        debug_return_int!(false as libc::c_int); /* not enough fields */
    }
    pathlen = ep.offset_from(path) as libc::c_long as size_t;

    /* Remainder is flags (freeform). */
    flags = sudo_strsplit_v1(
        std::ptr::null::<libc::c_char>(),
        entry_end,
        b" \t\0" as *const u8 as *const libc::c_char,
        &mut ep,
    );

    if flags.is_null() {
        debug_return_int!(false as libc::c_int); /* not enough fields */
    }

    /* If progname already exists, use it, else alloc a new one. */
    debug_spec = sudo_conf_data.debugging.tqh_first;
    while !debug_spec.is_null() {
        if strncmp((*debug_spec).progname, progname, prognamelen) == 0
            && *((*debug_spec).progname).offset(prognamelen as isize) as libc::c_int == '\0' as i32
        {
            break;
        }
        debug_spec = (*debug_spec).entries.tqe_next;
    }

    'oom: loop {
        if debug_spec.is_null() {
            debug_spec = malloc(::std::mem::size_of::<sudo_conf_debug>() as libc::c_ulong)
                as *mut sudo_conf_debug;

            if debug_spec.is_null() {
                break 'oom;
            }
            (*debug_spec).progname = strndup(progname, prognamelen);
            if (*debug_spec).progname.is_null() {
                free(debug_spec as *mut libc::c_void);
                debug_spec = std::ptr::null_mut::<sudo_conf_debug>();
                break 'oom;
            }

            // TAILQ_INIT(&debug_spec->debug_files);
            // TAILQ_INSERT_TAIL(&sudo_conf_data.debugging, debug_spec, entries);
            (*debug_spec).debug_files.tqh_first = std::ptr::null_mut::<sudo_debug_file>();
            (*debug_spec).debug_files.tqh_last = &mut (*debug_spec).debug_files.tqh_first;
            (*debug_spec).entries.tqe_next = std::ptr::null_mut::<sudo_conf_debug>();
            (*debug_spec).entries.tqe_prev = sudo_conf_data.debugging.tqh_last;
            *sudo_conf_data.debugging.tqh_last = debug_spec;
            sudo_conf_data.debugging.tqh_last = &mut (*debug_spec).entries.tqe_next;
        } // debug_spec.is_null()

        debug_file = calloc(1, ::std::mem::size_of::<sudo_debug_file>() as libc::c_ulong)
            as *mut sudo_debug_file;
        if debug_file.is_null() {
            break 'oom;
        }

        (*debug_file).debug_file = strndup(path, pathlen);
        if (*debug_file).debug_file.is_null() {
            break 'oom;
        }

        (*debug_file).debug_flags = strdup(flags);
        if (*debug_file).debug_flags.is_null() {
            break 'oom;
        }

        // TAILQ_INSERT_TAIL(&debug_spec->debug_files, debug_file, entries);
        ((*debug_file).entries.tqe_next) = std::ptr::null_mut::<sudo_debug_file>();
        (*debug_file).entries.tqe_prev = (*debug_spec).debug_files.tqh_last;
        *(*debug_spec).debug_files.tqh_last = debug_file;
        (*debug_spec).debug_files.tqh_last = &mut (*debug_file).entries.tqe_next;

        debug_return_int!(true as libc::c_int);
        break 'oom;
    } // oom:loop

    sudo_warnx!(
        b"%s: %s\0" as *const u8 as *const libc::c_char,
        get_function_name!(),
        b"unable to allocate memory\0"
    );

    if !debug_file.is_null() {
        free((*debug_file).debug_file as *mut libc::c_void);
        free((*debug_file).debug_flags as *mut libc::c_void);
        free(debug_file as *mut libc::c_void);
    }
    debug_return_int!(-(1 as libc::c_int));
}

/*
 * "Plugin symbol /path/to/log args..."
 */
#[no_mangle]
unsafe extern "C" fn parse_plugin(
    mut entry: *const libc::c_char,
    mut _conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    let mut info: *mut plugin_info = std::ptr::null_mut::<plugin_info>();
    let mut ep: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut path: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut symbol: *const libc::c_char = std::ptr::null::<libc::c_char>();
    let mut entry_end: *const libc::c_char = entry.offset(strlen(entry) as isize);
    let mut options: *mut *mut libc::c_char = std::ptr::null_mut::<*mut libc::c_char>();
    let mut pathlen: size_t = 0 as size_t;
    let mut symlen: size_t = 0 as size_t;
    let mut nopts: libc::c_uint = 0 as libc::c_uint;

    debug_decl!(SUDO_DEBUG_UTIL);

    /* Parse symbol. */
    symbol = sudo_strsplit_v1(
        entry,
        entry_end,
        b" \t\0" as *const u8 as *const libc::c_char,
        &mut ep,
    );

    if symbol.is_null() {
        debug_return_int!(false as libc::c_int); /* not enough fields */
    }

    symlen = ep.offset_from(symbol) as size_t;

    /* Parse path. */
    path = sudo_strsplit_v1(
        std::ptr::null::<libc::c_char>(),
        entry_end,
        b" \t\0" as *const u8 as *const libc::c_char,
        &mut ep,
    );
    if path.is_null() {
        debug_return_int!(false as libc::c_int); /* not enough fields */
    }
    pathlen = ep.offset_from(path) as size_t;

    /* Split options into an array if present. */
    while isblank!(*ep) != 0 {
        ep = ep.offset(1_isize);
    }

    'oom: loop {
        if *ep as libc::c_int != '\0' as i32 {
            /* Count number of options and allocate array. */
            let mut cp: *const libc::c_char = std::ptr::null::<libc::c_char>();
            let mut opt: *const libc::c_char = ep;

            /* Count and allocate options array. */
            nopts = 0;
            cp = sudo_strsplit_v1(
                opt,
                entry_end,
                b" \t\0" as *const u8 as *const libc::c_char,
                &mut ep,
            );
            while !cp.is_null() {
                nopts += 1;
                cp = sudo_strsplit_v1(
                    std::ptr::null::<libc::c_char>(),
                    entry_end,
                    b" \t\0" as *const u8 as *const libc::c_char,
                    &mut ep,
                );
            } // while !cp.is_null()

            options = reallocarray(
                std::ptr::null_mut::<libc::c_void>(),
                (nopts + 1) as size_t,
                ::std::mem::size_of::<*mut libc::c_char>() as libc::c_ulong,
            ) as *mut *mut libc::c_char;
            if options.is_null() {
                break 'oom;
            }

            /* Fill in options array. */
            nopts = 0;
            cp = sudo_strsplit_v1(
                opt,
                entry_end,
                b" \t\0" as *const u8 as *const libc::c_char,
                &mut ep,
            );

            loop {
                if cp.is_null() {
                    break;
                }
                let fresh0 = &mut (*options.offset(nopts as isize));
                *fresh0 = strndup(cp, ep.offset_from(cp) as libc::c_long as size_t);
                if (*options.offset(nopts as isize)).is_null() {
                    let fresh1 = &mut (*options.offset(nopts as isize));
                    *fresh1 = std::ptr::null_mut::<libc::c_char>();
                    break 'oom;
                }
                nopts = nopts.wrapping_add(1);

                cp = sudo_strsplit_v1(
                    std::ptr::null::<libc::c_char>(),
                    entry_end,
                    b" \t\0" as *const u8 as *const libc::c_char,
                    &mut ep,
                );
            }

            *options.offset(nopts as isize) = std::ptr::null_mut::<libc::c_char>();
        } //  if *ep  as libc::c_int != '\0' as i32

        info = calloc(
            ::core::mem::size_of::<plugin_info>() as libc::c_ulong,
            1 as libc::c_int as libc::c_ulong,
        ) as *mut plugin_info;

        if info.is_null() {
            break 'oom;
        }
        (*info).symbol_name = strndup(symbol, symlen);
        if ((*info).symbol_name).is_null() {
            break 'oom;
        }
        (*info).path = strndup(path, pathlen);
        if ((*info).path).is_null() {
            break 'oom;
        }
        (*info).options = options;
        (*info).lineno = lineno;

        //     TAILQ_INSERT_TAIL(&sudo_conf_data.plugins, info, entries);
        (*info).entries.tqe_next = std::ptr::null_mut::<plugin_info>();
        (*info).entries.tqe_prev = sudo_conf_data.plugins.tqh_last;
        *sudo_conf_data.plugins.tqh_last = info;
        sudo_conf_data.plugins.tqh_last = &mut (*info).entries.tqe_next;

        debug_return_int!(true as libc::c_int);

        break 'oom;
    } // oom loop

    sudo_warnx!(
        b"%s: %s\0" as *const u8 as *const libc::c_char,
        get_function_name!(),
        b"unable to allocate memory\0" as *const u8 as *const libc::c_char
    );

    if !options.is_null() {
        loop {
            let fresh2 = nopts;
            nopts = nopts.wrapping_sub(1);
            if fresh2 == 0 {
                break;
            }
            free(*options.offset(nopts as isize) as *mut libc::c_void);
        }

        free(options as *mut libc::c_void);
    }
    if !info.is_null() {
        free((*info).symbol_name as *mut libc::c_void);
        free((*info).path as *mut libc::c_void);
        free(info as *mut libc::c_void);
    }

    debug_return_int!(-(1 as libc::c_int));
}

#[no_mangle]
unsafe extern "C" fn set_var_disable_coredump(
    mut strval: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    // int val = sudo_strtobool(strval);
    let mut val: libc::c_int = sudo_strtobool_v1(strval);

    debug_decl!(SUDO_DEBUG_UTIL);

    if val == -1 {
        sudo_warnx!(
            b"invalid value for %s \"%s\" in %s, line %u\0" as *const u8 as *const libc::c_char,
            b"disable_coredump\0" as *const u8 as *const libc::c_char,
            strval,
            conf_file,
            lineno
        );

        debug_return_int!(false as libc::c_int);
    }

    sudo_conf_data.disable_coredump = val as libc::c_int != 0;

    debug_return_int!(true as libc::c_int)
}

#[no_mangle]
unsafe extern "C" fn set_var_group_source(
    mut strval: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    debug_decl!(SUDO_DEBUG_UTIL);

    if strcasecmp(strval, b"adaptive\0" as *const u8 as *const libc::c_char) == 0 {
        sudo_conf_data.group_source = GROUP_SOURCE_ADAPTIVE;
    } else if strcasecmp(strval, b"static\0" as *const u8 as *const libc::c_char) == 0 {
        sudo_conf_data.group_source = GROUP_SOURCE_STATIC;
    } else if strcasecmp(strval, b"dynamic\0" as *const u8 as *const libc::c_char) == 0 {
        sudo_conf_data.group_source = GROUP_SOURCE_DYNAMIC;
    } else {
        sudo_warnx!(
            b"unsupported group source \"%s\" in %s, line %u\0" as *const u8 as *const libc::c_char,
            strval,
            conf_file,
            lineno
        );
        debug_return_int!(false as libc::c_int);
    }
    debug_return_int!(true as libc::c_int)
}

#[no_mangle]
unsafe extern "C" fn set_var_max_groups(
    mut strval: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    let mut max_groups: libc::c_int = 0 as libc::c_int;
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        max_groups = sudo_strtonum(
            strval,
            1,
            INT_MAX!(),
            std::ptr::null_mut::<*const libc::c_char>(),
        ) as libc::c_int;
        if max_groups <= 0 {
            sudo_warnx!(
                b"invalid max groups \"%s\" in %s, line %u\0" as *const u8 as *const libc::c_char,
                strval,
                conf_file,
                lineno
            );
            debug_return_int!(false as libc::c_int);
        }
        sudo_conf_data.max_groups = max_groups;
        debug_return_int!(true as libc::c_int)
    } //unsafe
}

#[no_mangle]
unsafe extern "C" fn set_var_probe_interfaces(
    mut strval: *const libc::c_char,
    mut conf_file: *const libc::c_char,
    mut lineno: libc::c_uint,
) -> libc::c_int {
    let mut val: libc::c_int = sudo_strtobool_v1(strval);
    debug_decl!(SUDO_DEBUG_UTIL);

    if val == -1 {
        sudo_warnx!(
            b"invalid value for %s \"%s\" in %s, line %u\0" as *const u8 as *const libc::c_char,
            b"probe_interfaces\0" as *const u8 as *const libc::c_char,
            strval,
            conf_file,
            lineno,
        );
        debug_return_int!(false as libc::c_int);
    }

    sudo_conf_data.probe_interfaces = val as libc::c_int != 0;
    debug_return_int!(true as libc::c_int)
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_askpass_path_v1() -> *const libc::c_char {
    sudo_conf_data.path_table[SUDO_CONF_PATH_ASKPASS as usize].pval
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_sesh_path_v1() -> *const libc::c_char {
    sudo_conf_data.path_table[SUDO_CONF_PATH_SESH as usize].pval
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_noexec_path_v1() -> *const libc::c_char {
    sudo_conf_data.path_table[SUDO_CONF_PATH_NOEXEC as usize].pval
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_plugin_dir_path_v1() -> *const libc::c_char {
    sudo_conf_data.path_table[SUDO_CONF_PATH_PLUGIN_DIR as usize].pval
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_devsearch_path_v1() -> *const libc::c_char {
    sudo_conf_data.path_table[SUDO_CONF_PATH_DEVSEARCH as usize].pval
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_group_source_v1() -> libc::c_int {
    sudo_conf_data.group_source
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_max_groups_v1() -> libc::c_int {
    sudo_conf_data.max_groups
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_plugins_v1() -> *mut plugin_info_list {
    &mut sudo_conf_data.plugins
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_debugging_v1() -> *mut sudo_conf_debug_list {
    &mut sudo_conf_data.debugging
}

/* Return the debug files list for a program, or NULL if none. */
#[no_mangle]
pub fn sudo_conf_debug_files_v1(progname: *const libc::c_char) -> *mut sudo_conf_debug_file_list {
    let mut debug_spec: *mut sudo_conf_debug = std::ptr::null_mut::<sudo_conf_debug>();
    let mut prognamelen: size_t = 0 as size_t;
    let mut progbaselen: size_t = 0 as size_t;
    let mut progbase: *const libc::c_char = progname;

    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        /* Determine basename if program is fully qualified (like for plugins). */
        prognamelen = strlen(progname) as size_t;
        progbaselen = prognamelen;
        if *progname as libc::c_int == '/' as i32 {
            progbase = strrchr(progname, '/' as i32);
            progbase = progbase.offset(1_isize);
            progbaselen = strlen(progbase);
        }

        /* Convert utsudoedit -> utsudo. */
        if progbaselen > 6
            && strcmp(
                progbase.offset(6_isize),
                b"edit\0" as *const u8 as *const libc::c_char,
            ) == 0
        {
            //progbaselen = progbaselen - 6;
            progbaselen -= 6;
        }

        debug_spec = sudo_conf_data.debugging.tqh_first;
        while !debug_spec.is_null() {
            let mut prog: *const libc::c_char = progbase;
            let mut len: size_t = progbaselen;

            if *((*debug_spec).progname).offset(0_isize) as libc::c_int == '/' as i32 {
                /* Match fully-qualified name, if possible. */
                prog = progname;
                len = prognamelen;
            }
            if strncasecmp((*debug_spec).progname, prog, len) == 0
                && *((*debug_spec).progname).offset(len as isize) as libc::c_int == '\u{0}' as i32
            {
                debug_return_ptr!(
                    &mut ((*debug_spec).debug_files) as *mut sudo_conf_debug_file_list
                );
            }
            debug_spec = (*debug_spec).entries.tqe_next;
        } //  while !debug_spec.is_null()

        debug_return_ptr!(std::ptr::null_mut::<sudo_conf_debug_file_list>());
    } //unsafe
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_disable_coredump_v1() -> bool {
    sudo_conf_data.disable_coredump
}

#[no_mangle]
pub unsafe extern "C" fn sudo_conf_probe_interfaces_v1() -> bool {
    sudo_conf_data.probe_interfaces
}

/*
 * Reads in /etc/utsudo.conf and populates sudo_conf_data.
 */
#[no_mangle]
pub fn sudo_conf_read_v1(
    mut conf_file: *const libc::c_char,
    mut conf_types: libc::c_int,
) -> libc::c_int {
    let mut sb: stat = sb_all_arch;
    let mut fp: *mut FILE = std::ptr::null_mut::<FILE>();
    let mut ret: libc::c_int = false as libc::c_int;

    let mut prev_locale: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut line: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();
    let mut conf_lineno: libc::c_uint = 0 as libc::c_uint;
    let mut linesize: size_t = 0 as size_t;

    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        prev_locale = setlocale(LC_ALL, std::ptr::null::<libc::c_char>());
        if prev_locale.is_null() {
            sudo_warn!(b"setlocale(LC_ALL, NULL)\0" as *const u8 as *const libc::c_char,);
            debug_return_int!(-(1 as libc::c_int));
        }

        prev_locale = strdup(prev_locale);
        if prev_locale.is_null() {
            sudo_warnx!(
                b"%s: %s\0" as *const u8 as *const libc::c_char,
                get_function_name!(),
                b"unable to allocate memory\0" as *const u8 as *const libc::c_char
            );
            debug_return_int!(-(1 as libc::c_int));
        }

        /* Parse sudo.conf in the "C" locale. */
        if *prev_locale.offset(0_isize) as libc::c_int != 'C' as i32
            || *prev_locale.offset(1_isize) as libc::c_int != '\u{0}' as i32
        {
            setlocale(LC_ALL, b"C\0" as *const u8 as *mut libc::c_char);
        }

        'done: loop {
            if conf_file.is_null() {
                conf_file = _PATH_SUDO_CONF!();
                match sudo_secure_file_v1(
                    conf_file,
                    ROOT_UID as uid_t,
                    -(1 as libc::c_int) as gid_t,
                    &mut sb,
                ) {
                    SUDO_PATH_SECURE => {
                        // break 'done;
                    }
                    SUDO_PATH_MISSING => {
                        /* Root should always be able to read sudo.conf. */
                        if *__errno_location() != ENOENT && geteuid() == ROOT_UID as libc::c_uint {
                            sudo_warn!(
                                b"unable to stat %s\0" as *const u8 as *const libc::c_char,
                                conf_file
                            );
                        }

                        break 'done;
                    }
                    SUDO_PATH_BAD_TYPE => {
                        sudo_warnx!(
                            b"%s is not a regular file\0" as *const u8 as *const libc::c_char,
                            conf_file
                        );
                        break 'done;
                    }
                    SUDO_PATH_WRONG_OWNER => {
                        sudo_warnx!(
                            b"%s is owned by uid %u, should be %u\0" as *const u8
                                as *const libc::c_char,
                            conf_file,
                            (sb.st_uid) as libc::c_uint,
                            ROOT_UID
                        );
                        break 'done;
                    }
                    SUDO_PATH_WORLD_WRITABLE => {
                        sudo_warnx!(
                            b"%s is world writable\0" as *const u8 as *const libc::c_char,
                            conf_file
                        );
                        break 'done;
                    }
                    SUDO_PATH_GROUP_WRITABLE => {
                        sudo_warnx!(
                            b"%s is group writable\0" as *const u8 as *const libc::c_char,
                            conf_file
                        );
                        break 'done;
                    }
                    _ => {
                        /* NOTREACHED */
                        break 'done;
                    }
                } //match sudo_secure_file_v1
            } // cong_file.is_null

            fp = fopen(conf_file, b"r\0" as *const u8 as *const libc::c_char);
            if fp.is_null() {
                if *__errno_location() != ENOENT && geteuid() == ROOT_UID as libc::c_uint {
                    sudo_warn!(
                        b"unable to open %s\0" as *const u8 as *const libc::c_char,
                        conf_file
                    );
                } // *__errno_location() != ENOENT
                break 'done;
            } // fp.is_null()

            while sudo_parseln_v2(
                &mut line,
                &mut linesize,
                &mut conf_lineno,
                fp as *mut FILE,
                0 as libc::c_int,
            ) != -1
            {
                let mut cur: *mut sudo_conf_table = std::ptr::null_mut::<sudo_conf_table>();
                let mut i: libc::c_int = 0 as libc::c_int;
                let mut cp: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();

                cp = line;
                if *cp as libc::c_int == '\u{0}' as i32 {
                    continue; /* empty line or comment */
                }

                cur = sudo_conf_table.as_mut_ptr();
                while !(*cur).name.is_null() {
                    if strncasecmp(cp, (*cur).name, (*cur).namelen as libc::c_ulong) == 0
                        && isblank!(*cp.offset((*cur).namelen as isize) as isize) != 0
                    {
                        if ISSET!(conf_types, (1 << i)) != 0 {
                            cp = cp.offset((*cur).namelen as isize);

                            while isblank!(*cp) != 0 {
                                cp = cp.offset(1_isize);
                            } //while isblank cp
                            ret = ((*cur).parser).expect("non-null function pointer")(
                                cp,
                                conf_file,
                                conf_lineno,
                            );
                            if ret == -1 {
                                break 'done;
                            }
                        } // ISSET
                        break;
                    } // if strncasecmp
                    i = i.wrapping_add(1);
                    cur = cur.offset(1);
                } // while (*cur).name.is_null()

                if ((*cur).name).is_null() {
                    sudo_debug_printf!(
                        SUDO_DEBUG_WARN,
                        b"%s: %s:%u: unsupported entry: %s\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        conf_file,
                        conf_lineno,
                        line
                    );
                }
            } // while sudo_parseln_v2
            ret = true as libc::c_int;

            break 'done;
        } // done loop

        if !fp.is_null() {
            fclose(fp);
        }
        free(line as *mut libc::c_void);

        /* Restore locale if needed. */
        if *prev_locale.offset(0_isize) as libc::c_int != 'C' as i32
            || *prev_locale.offset(1_isize) as libc::c_int != '\u{0}' as i32
        {
            setlocale(LC_ALL, prev_locale);
        }
        free(prev_locale as *mut libc::c_void);

        debug_return_int!(ret)
    } //unsafe
}

/*
 * Used by the sudo_conf regress test to clear compile-time path settings.
 */
#[no_mangle]
pub fn sudo_conf_clear_paths_v1() {
    let mut cur: *mut sudo_conf_path_table = std::ptr::null_mut::<sudo_conf_path_table>();
    unsafe {
        debug_decl!(SUDO_DEBUG_UTIL);

        cur = (sudo_conf_data.path_table).as_mut_ptr();
        while !((*cur).pname).is_null() {
            if (*cur).dynamic {
                free((*cur).pval as *mut libc::c_void);
            }
            (*cur).pval = std::ptr::null_mut::<libc::c_char>();
            (*cur).dynamic = false;
            cur = cur.offset(1);
        }
    } //unsafe
}

unsafe extern "C" fn run_static_initializers() {
    sudo_conf_table = [
        {
            sudo_conf_table {
                name: b"Debug\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 6]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    parse_debug
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"Path\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 5]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    parse_path
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"Plugin\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 7]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    parse_plugin
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"Set\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 4]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    parse_variable
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: std::ptr::null::<libc::c_char>(),
                namelen: 0,
                parser: None,
            }
            //init
        },
    ];

    sudo_conf_var_table = [
        {
            sudo_conf_table {
                name: b"disable_coredump\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 17]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    set_var_disable_coredump
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"group_source\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 13]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    set_var_group_source
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"max_groups\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    set_var_max_groups
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: b"probe_interfaces\0" as *const u8 as *const libc::c_char,
                namelen: (::std::mem::size_of::<[libc::c_char; 17]>() as libc::c_ulong)
                    .wrapping_sub(1 as libc::c_int as libc::c_ulong)
                    as libc::c_uint,
                parser: Some(
                    set_var_probe_interfaces
                        as unsafe extern "C" fn(
                            *const libc::c_char,
                            *const libc::c_char,
                            libc::c_uint,
                        ) -> libc::c_int,
                ),
            }
            //init
        },
        {
            sudo_conf_table {
                name: std::ptr::null::<libc::c_char>(),
                namelen: 0,
                parser: None,
            }
            //init
        },
    ];

    sudo_conf_data = {
        sudo_conf_data {
            disable_coredump: true,
            probe_interfaces: true,
            group_source: GROUP_SOURCE_ADAPTIVE,
            max_groups: -1,
            debugging: {
                sudo_conf_debug_list {
                    tqh_first: std::ptr::null_mut::<sudo_conf_debug>(),
                    tqh_last: &mut sudo_conf_data.debugging.tqh_first,
                }
                //init
            },
            plugins: {
                plugin_info_list {
                    tqh_first: std::ptr::null_mut::<plugin_info>(),
                    tqh_last: &mut sudo_conf_data.plugins.tqh_first,
                }
                //init
            },
            path_table: [
                {
                    sudo_conf_path_table {
                        pname: b"askpass\0" as *const u8 as *const libc::c_char,
                        pnamelen: (::std::mem::size_of::<[libc::c_char; 8]>() as libc::c_ulong)
                            .wrapping_sub(1) as libc::c_uint,
                        dynamic: false,
                        pval: _PATH_SUDO_ASKPASS!(),
                    }
                    //askpass
                },
                {
                    sudo_conf_path_table {
                        pname: b"sesh\0" as *const u8 as *const libc::c_char,
                        pnamelen: (::std::mem::size_of::<[libc::c_char; 5]>() as libc::c_ulong)
                            .wrapping_sub(1) as libc::c_uint,
                        dynamic: false,
                        pval: _PATH_SUDO_SESH!(),
                    }
                    //sesh
                },
                {
                    sudo_conf_path_table {
                        pname: b"noexec\0" as *const u8 as *const libc::c_char,
                        pnamelen: (::std::mem::size_of::<[libc::c_char; 7]>() as libc::c_ulong)
                            .wrapping_sub(1) as libc::c_uint,
                        dynamic: false,
                        pval: _PATH_SUDO_NOEXEC!(),
                    }
                    //noexec
                },
                {
                    sudo_conf_path_table {
                        pname: b"plugin_dir\0" as *const u8 as *const libc::c_char,
                        pnamelen: (::std::mem::size_of::<[libc::c_char; 11]>() as libc::c_ulong)
                            .wrapping_sub(1) as libc::c_uint,
                        dynamic: false,
                        pval: _PATH_SUDO_PLUGIN_DIR!(),
                    }
                    //plugin_dir
                },
                {
                    sudo_conf_path_table {
                        pname: b"devsearch\0" as *const u8 as *const libc::c_char,
                        pnamelen: (::std::mem::size_of::<[libc::c_char; 10]>() as libc::c_ulong)
                            .wrapping_sub(1) as libc::c_uint,
                        dynamic: false,
                        pval: _PATH_SUDO_DEVSEARCH!(),
                    }
                    //devsearch
                },
                {
                    sudo_conf_path_table {
                        pname: std::ptr::null::<libc::c_char>(),
                        pnamelen: 0 as libc::c_uint,
                        dynamic: false,
                        //pval: std::ptr::null::<libc::c_char>(),
                        //pval: 0 as *mut libc::c_char,
                        pval: std::ptr::null_mut::<libc::c_char>(),
                    }
                    //null
                },
            ],
        }
        //init
    };
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers];
